package cn.com.twoke.application.game.mario.core.ecs.system;

import cn.com.twoke.application.game.mario.core.ecs.component.ColliderComponent;
import cn.com.twoke.application.game.mario.core.ecs.component.PositionComponent;
import cn.com.twoke.application.game.mario.core.ecs.component.RigidbodyComponent;
import cn.com.twoke.application.game.mario.core.ecs.entity.Entity;
import cn.com.twoke.application.game.mario.game.component.AutoMoveComponent;
import cn.com.twoke.application.game.mario.game.entity.EntityType;

import java.util.ArrayList;
import java.util.List;

public class PhysicsSystem implements LogicGameSystem {
    private final cn.com.twoke.application.game.mario.game.config.GameConfig config = cn.com.twoke.application.game.mario.game.config.GameConfig.getInstance();

    @Override
    public void update(List<Entity> entities, double delta) {
        updatePhysicsStep(entities, (float) delta);
    }

    private void updatePhysicsStep(List<Entity> entities, float delta) {
        // 分组实体
        List<Entity> dynamicEntities = new ArrayList<>();
        List<Entity> staticColliders = new ArrayList<>();

        for (Entity entity : entities) {
            if (entity.hasComponent(ColliderComponent.class)) {
                if (entity.hasComponent(RigidbodyComponent.class) && entity.getComponent(RigidbodyComponent.class).bodyType == RigidbodyComponent.BodyType.DYNAMIC) {
                    dynamicEntities.add(entity);
                } else {
                    staticColliders.add(entity);
                }
            }
        }
        // 处理动态实体
        for (Entity dynamic : dynamicEntities) {
            RigidbodyComponent rb = dynamic.getComponent(RigidbodyComponent.class);
            PositionComponent pos = dynamic.getComponent(PositionComponent.class);
            ColliderComponent col = dynamic.getComponent(ColliderComponent.class);

            // 应用重力
            if (rb.useGravity && !rb.isGrounded) {
                rb.velocity.y += config.getGravity() * rb.gravityScale * delta / 60;
            }

            // 临时移动
            float newX = pos.x + rb.velocity.x;
            float newY = pos.y + rb.velocity.y;

            // 重置地面状态
            rb.isGrounded = false;

            // 检测与所有静态碰撞体的碰撞
            for (Entity staticCol : staticColliders) {
                PositionComponent staticPos = staticCol.getComponent(PositionComponent.class);
                ColliderComponent staticColComp = staticCol.getComponent(ColliderComponent.class);

                // 预测碰撞
                if (checkCollision(newX, newY, col.shape.get().getBounds().width, col.shape.get().getBounds().height, staticPos.x, staticPos.y, staticColComp.shape.get().getBounds().width, staticColComp.shape.get().getBounds().height)) {


                    // 解决碰撞
                    CollisionResolution res = resolveCollision(newX, newY, col.shape.get().getBounds().width, col.shape.get().getBounds().height, rb.velocity.x, rb.velocity.y, staticPos.x, staticPos.y, staticColComp.shape.get().getBounds().width, staticColComp.shape.get().getBounds().height, staticColComp.type);

                    newX = res.newX;
                    newY = res.newY;
                    rb.velocity.x = res.newVelX;
                    rb.velocity.y = res.newVelY;

                    if (res.isGrounded) {
                        rb.isGrounded = true;
                        rb.velocity.x = 0;
                        rb.velocity.y = 0;
                    }

                    if (dynamic.hasComponent(AutoMoveComponent.class) && staticCol.getType() != EntityType.GROUND) {
                        AutoMoveComponent component = dynamic.getComponent(AutoMoveComponent.class);
                        component.reverseDirection(); // 反向
                    }
                }
            }

            // 应用最终位置
            pos.x = newX;
            pos.y = newY;
        }
    }


    private boolean checkCollision(float x1, float y1, int w1, int h1, float x2, float y2, int w2, int h2) {
        return x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2;
    }

    private CollisionInfo checkCollisionWithInfo(float x1, float y1, int w1, int h1, float x2, float y2, int w2, int h2) {
        float overlapX = Math.min(x1 + w1 - x2, x2 + w2 - x1);
        float overlapY = Math.min(y1 + h1 - y2, y2 + h2 - y1);
        
        if (overlapX > 0 && overlapY > 0) {
            // 确定最小分离向量
            if (overlapX < overlapY) {
                // 水平分离
                float separationX = (x1 < x2) ? -overlapX : overlapX;
                return new CollisionInfo(true, separationX, 0, overlapX);
            } else {
                // 垂直分离
                float separationY = (y1 < y2) ? -overlapY : overlapY;
                return new CollisionInfo(true, 0, separationY, overlapY);
            }
        }
        
        return new CollisionInfo(false, 0, 0, 0);
    }

    private CollisionResolution resolveCollision(float dynamicX, float dynamicY, int dynamicW, int dynamicH, float velX, float velY, float staticX, float staticY, int staticW, int staticH, ColliderComponent.Type type) {

        CollisionResolution res = new CollisionResolution();
        res.newX = dynamicX;
        res.newY = dynamicY;
        res.newVelX = velX;
        res.newVelY = velY;

        // 使用改进的碰撞检测获取更多信息
        CollisionInfo collisionInfo = checkCollisionWithInfo(dynamicX, dynamicY, dynamicW, dynamicH, staticX, staticY, staticW, staticH);
        
        if (collisionInfo.isColliding) {
            // 根据最小分离向量解决碰撞
            if (collisionInfo.separationX != 0) {
                // 水平碰撞
                res.newX = dynamicX + collisionInfo.separationX + Math.signum(collisionInfo.separationX) * config.getCollisionTolerance();
                res.newVelX = 0;
            } else if (collisionInfo.separationY != 0) {
                // 垂直碰撞
                res.newY = dynamicY + collisionInfo.separationY + Math.signum(collisionInfo.separationY) * config.getCollisionTolerance();
                res.newVelY = 0;
                
                // 如果是从上方碰撞且不是单向平台，则标记为接地
                if (collisionInfo.separationY < 0 && type != ColliderComponent.Type.ONE_WAY) {
                    res.isGrounded = true;
                }
            }
        }

        return res;
    }

    private static class CollisionResolution {
        public float newX, newY;
        public float newVelX, newVelY;
        public boolean isGrounded = false;
    }
    
    private static class CollisionInfo {
        public boolean isColliding;
        public float separationX, separationY;
        public float overlapDepth;
        
        public CollisionInfo(boolean isColliding, float separationX, float separationY, float overlapDepth) {
            this.isColliding = isColliding;
            this.separationX = separationX;
            this.separationY = separationY;
            this.overlapDepth = overlapDepth;
        }
    }

}